package com.caissa.framework.starter.autoconfigure.instrument.aop.spring;

import com.caissa.framework.starter.autoconfigure.AspectBase;
import com.caissa.framework.starter.autoconfigure.annotation.ExceptionTransformer;
import com.caissa.framework.starter.autoconfigure.common.CatContext;
import com.caissa.framework.starter.autoconfigure.common.CatHttpConstants;
import com.dianping.cat.Cat;
import com.dianping.cat.message.Message;
import com.dianping.cat.message.Transaction;
import com.dianping.cat.message.internal.NullMessage;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;

import static com.caissa.framework.starter.autoconfigure.common.CatHttpConstants.*;

/**
 * Description:
 * User: forest
 * Date: 2021-01-12 11:25 上午
 */
@Slf4j
@Aspect
public class SpringWebHandlerAdvise extends AspectBase {

    @Override
    protected String getMetricType() {
        return CAT_RPC_SERVICE;
    }

    @Around("execution(* org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handleInternal(..))")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {

        Object[] args = pjp.getArgs();
        HttpServletRequest request = null;
        Transaction t;

        try {
            request = (HttpServletRequest) args[0];
            String url = request.getRequestURL().toString();
            String requestURI = request.getRequestURI();

            if (url.contains("actuator") || url.contains("swagger") || url.contains("api-docs")) {
                return pjp.proceed();
            }

            CatContext catContext = new CatContext();
            catContext.addProperty(Cat.Context.ROOT, request.getHeader(CatHttpConstants.CAT_HTTP_HEADER_ROOT_MESSAGE_ID));
            catContext.addProperty(Cat.Context.PARENT, request.getHeader(CatHttpConstants.CAT_HTTP_HEADER_PARENT_MESSAGE_ID));
            catContext.addProperty(Cat.Context.CHILD, request.getHeader(CatHttpConstants.CAT_HTTP_HEADER_CHILD_MESSAGE_ID));
            Cat.logRemoteCallServer(catContext);

            String clientIp = request.getHeader(CatHttpConstants.CAT_HTTP_HEADER_CLIENT_IP);
            String clientAppId = request.getHeader(CatHttpConstants.CAT_HTTP_HEADER_CLIENT_APPNAME);

            t = Cat.newTransaction(getMetricType(), requestURI);

            if (clientIp != null) {
                Cat.logEvent(CAT_RPC_SERVICE_CLIENT_IP, clientIp);
            }

            if (clientAppId!=null) {
                Cat.logEvent(CAT_RPC_SERVICE_CLIENT_APPID, clientAppId);
            }
        } catch (Exception e) {
            e.printStackTrace();
            t = NullMessage.TRANSACTION;
        }

        try {
            StringBuffer params = new StringBuffer();
            Enumeration<String> parameterNames = request.getParameterNames();
            int index = 0;
            while (parameterNames.hasMoreElements()) {
                if (index == 0) {
                    params.append("?");
                } else {
                    params.append("&");
                }
                index++;
                String paramName = parameterNames.nextElement();
                String paramVal = request.getParameter(paramName);
                if (paramVal == null) {
                    paramVal = "";
                } else if (paramVal.length() > CAT_HTTP_RECORD_MAX_LENGTH_OF_PARAM) {
                    paramVal = paramVal.substring(0,CAT_HTTP_RECORD_MAX_LENGTH_OF_PARAM);
                }
                params.append(paramName).append("=").append(paramVal);
            }

            Cat.logEvent(CAT_URL+".method", request.getMethod(), Message.SUCCESS, request.getRequestURL().toString()+params.toString());
            Cat.logEvent(CAT_URL+".client", request.getRemoteHost());

            Object obj = pjp.proceed();
            t.setStatus(Transaction.SUCCESS);

            return obj;
        } catch (Throwable e) {
            t.setStatus(e);
            log.error("",e);
            ExceptionTransformer.ifThrowCheckedException(e);
            throw new RuntimeException("", e);
        } finally {
            t.complete();
        }
    }
}
